package com.google.code.chaotic.updates;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheManager;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.datanucleus.store.appengine.query.JDOCursorHelper;
import org.restlet.resource.Post;
import org.restlet.resource.Put;
import org.restlet.resource.ServerResource;

import com.google.appengine.api.datastore.Cursor;
import com.google.code.chaotic.ConversionUtil;
import com.google.code.chaotic.dto.CommuterDto;
import com.google.code.chaotic.dto.CommutingServiceDto;
import com.google.code.chaotic.model.Commuter;
import com.google.code.chaotic.model.CommutingService;
import com.google.code.chaotic.model.HabitInService;
import com.google.code.chaotic.server.PmFactory;

/**
 * Resource which has only one representation.
 * 
 */
public class FrontTierUpdatesResourceImpl extends ServerResource //
		implements FrontTierUpdatesResource {

	private static Logger logger = Logger.getLogger(//
			FrontTierUpdatesResourceImpl.class.getName());

	//

	@Post
	@Override
	public CommuterDto[] listCommuters(Integer maxCount) {
		logger.info("\"commuters list\" request received!");
		Cache cache;
		try {
			cache = CacheManager.getInstance().getCacheFactory().createCache(
					Collections.EMPTY_MAP);

		} catch (CacheException e) {
			logger.log(Level.SEVERE, e.toString(), e);
			throw new RuntimeException(e);
		}

		String cursorKey = "Commuter Cursor";
		String cursorString = (String) cache.get(cursorKey);

		PersistenceManager pm = PmFactory.get().getPersistenceManager();
		Query query = pm.newQuery(Commuter.class);
		List<Commuter> list = null;
		Cursor cursor = null;
		try {
			if (cursorString != null) {
				cursor = Cursor.fromWebSafeString(cursorString);
				HashMap<String, Object> map = new HashMap<String, Object>();
				map.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
				query.setExtensions(map);
			}
			query.setRange(0, maxCount);
			int maxTries = 5;
			int tryNo = 1;
			while (tryNo <= maxTries) {
				try {
					list = (List<Commuter>) query.execute();
					cursor = JDOCursorHelper.getCursor(list);
					if (list.size() < maxCount)
						cache.remove(cursorKey);
					else
						cache.put(cursorKey, cursor.toWebSafeString());

					break;

				} catch (Throwable th) {
					if (tryNo < maxTries) {
						String msg = String.format(//
								"Try %1$d: %2$s#", //
								tryNo, th.toString());
						logger.log(Level.SEVERE, msg, th);
						tryNo++;
						continue;

					} else
						throw new RuntimeException(th);
				}
			}
			CommuterDto[] array = new CommuterDto[list.size()];
			for (int i = 0; i < array.length; i++)
				array[i] = ConversionUtil.entityToDto(list.get(i));

			String format = ">>>>>>>> %1$d CommuterDto(s) are about to be serialized... (try #%2$d)";
			logger.info(String.format(format, array.length, tryNo));
			return array;

		} finally {
			pm.close();
		}
	}

	@Put
	@Override
	public String addCommutingService(CommutingServiceDto dto) {
		logger.info("\"commutung service addition\" request received!");
		PersistenceManager pm = PmFactory.get().getPersistenceManager();
		try {
			CommutingService entity = ConversionUtil.dtoToEntity(dto);
			List<HabitInService> hisList = entity.getHabits();
			for (HabitInService his : hisList)
				his.setServiceId(his.getServiceId());
			entity.setId(null);
			pm.makePersistent(entity);

		} finally {
			pm.close();
		}
		return dto.getId();
	}
}